#include "precompile.h"

#include "View.h"
#include "Document.h"
#include "Application.h"
#include "Layout.h"
#include "Controller.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

View::View()
{
	m_hascreated = false;
	m_active = false;
}

View::~View()
{
}

void View::Create(uintptr context,const Size& size)
{
	m_scale = 1.0f;
	m_hascreated = true;
	m_document = NULL;
	m_clientSize = size;
	m_eventHandlers.CreateObject(CLSID_EventHandlers);
	m_interaction.CreateObject(CLSID_Interaction);

	m_displayworkflow = getPresentationRuntime()->CreateWorkflow(L"DISPLAY");
	sys::InterfacePtr<IPresentationWorkflow> pIFPresetationWorkflow(m_displayworkflow);
	DisplayPresentationContext displayContext(NULL,context,size,m_scale);
	pIFPresetationWorkflow->Prepare(displayContext);

	IEventHandlers::InteractionInput input = {GetGraphics(),GetInteraction()};
	GetEventHandlers()->StartEvents(input);
}

bool View::IsActive()
{
	return m_active;
}

void View::SetActive(bool active/*=true*/)
{
	m_active = active;

	Application* applicaiton = (Application*)GetApplication();
	if (m_active)
		applicaiton->SetActiveView(this);
	else
		applicaiton->SetActiveView(NULL);

	IDocument* document = GetDocument();
	if (document)
		applicaiton->GetController()->ActivateControl(this,document);
}

bool View::Event(SystemEventArgs* e)
{
	if (!m_hascreated)
		return false;

	SetActive(true);

	//localize the region
	GetInteraction()->ActiveRegion(0u);

	Point worldlocation = GetGraphics()->CoordinateDeviceToWorld(e->GetPhysicalLocation());
	e->SetLocation(worldlocation);

	if (e->MouseWheel() && (e->LeftCtrlKeyDown()||(e->RightCtrlKeyDown())))
	{
		if (e->GetWheelDelta() < 0)
			m_scale /= 1.1f;
		else
			m_scale *= 1.1f;
		Refresh();
		Scroll();
		return true;
	}
	else
		return GetEventHandlers()->Event(e);
}

void View::Close()
{
	m_hascreated = false;
	SetActive(false);

	GetApplication()->GetController()->CloseControl(this,GetDocument());

	Document* documentclass = (Document*)GetDocument();
	documentclass->RemoveView(this);
}

void View::LinkDocument(IDocument* document)
{
	m_document  =document;

	Document* documentclass = (Document*)m_document;
	documentclass->AddView(this);

	Scroll();
}

Graphics* View::GetGraphics() const
{
	sys::InterfacePtr<IPresentationWorkflow> pIFDisplayworkflow(m_displayworkflow);
	return pIFDisplayworkflow->GetGraphics();
}

IEventHandlers* View::GetEventHandlers() const
{
	return sys::InterfacePtr<IEventHandlers>(m_eventHandlers);
}

IInteraction* View::GetInteraction() const
{
	return sys::InterfacePtr<IInteraction>(m_interaction);
}

void View::Update(IView* activeView)
{
	if (activeView == this){
		//get the state context to update
	  	const objectarray& selection = GetStateContext()->GetSelection();
		Refresh();
	}
	else
		Refresh();
}

IDocument* View::GetDocument() const
{
	return m_document;
}

void View::Draw(uintptr context,const Size& size)
{
	if(!GetDocument())
		return;

	m_clientSize = size;

	DisplayPresentationContext displayContext(GetDocument()->GetRoot(),context,size,m_scale);
	sys::InterfacePtr<IPresentationWorkflow> pIFDisplayworkflow(m_displayworkflow);
	pIFDisplayworkflow->Present(displayContext);

	GetEventHandlers()->Draw();

	DoLayout();
}

//////////////////////////////////////////////////////////////////////////
//private methods
void View::Refresh()
{
	CanvasRefreshing()(Rect(),true);
}

void View::Refresh(const Rect& boundbox)
{
	Rect pixelBoundbox = GetGraphics()->CoordinateWorldToDevice(boundbox);
	CanvasRefreshing()(pixelBoundbox,false);
}

void View::Scroll()
{
	Scrolling()(GetDeviceSize());
}

StateContext* View::GetStateContext()
{
	m_stateContext.SetActiveTarget(0u);
	return &m_stateContext;
}

real View::GetScale() const
{
	return m_scale;
}

void View::Scale(real scale,bool increase/*=true*/)
{
	if (increase)	
	{
		m_scale *= scale;
	}
	else	
	{
		m_scale /= scale;
	}
	GetGraphics()->SetPageScale(m_scale);
	Refresh();
	Scroll();
}

bool View::DoLayout() 
{
	m_layout = PageLayoutInfo();

	Point ptworld= GetGraphics()->CoordinateDeviceToWorld(Point(m_clientSize.cx,m_clientSize.cy));
	Size clientSize = Size(ptworld.x,ptworld.y);

	sys::ServiceInterfacePtr<IHierarchyService> pIFHierarchyService(HIERARCHY_SERVICE);
	objectarray pages;
	pIFHierarchyService->GetPages(GetDocument()->GetRoot(),pages);
	sys::InterfacePtr<IPage> pIFPage(pages[0]);
	Size pagesize(GetGraphics()->UnitMMtoLine(pIFPage->getPageWidth()),
							 GetGraphics()->UnitMMtoLine(pIFPage->getPageHeight()));
	PageLayout layout(clientSize,pagesize,pages.size(),Point(0,0));
	layout.Layout();
	m_layout = layout.GetResult();

	Points pts;
	for (uint32 i = 0; i < m_layout.pages.size(); ++i)
		pts.push_back(m_layout.pages[i].viewpoint);
	GetInteraction()->ActiveView(pts);

	return true;
}

Size View::GetDeviceSize()
{
	DoLayout();

	objectarray pages;
	sys::ServiceInterfacePtr<IHierarchyService> pIFHierarchyService(HIERARCHY_SERVICE);
	pIFHierarchyService->GetPages(GetDocument()->GetRoot(),pages);
	sys::InterfacePtr<IPage> pIFPage(pages[0]);
	Size pagesize(GetGraphics()->UnitMMtoLine(pIFPage->getPageWidth()),
							 GetGraphics()->UnitMMtoLine(pIFPage->getPageHeight()));
	Size size(pagesize.cx*m_layout.h_pagecount,
					pagesize.cy*m_layout.v_pagecount);

	Point ptDevice = GetGraphics()->CoordinateWorldToDevice(Point(size.cx,size.cy));
	size = Size(ptDevice.x,ptDevice.y);

	return size;
}

void View::SetViewPoint(const Point& viewpoint)
{
	m_viewpoint = viewpoint;
}

const Point& View::GetViewPoint() const
{
	return m_viewpoint;
}

IApplication* View::GetApplication()
{
	sys::ObjectPtr objApplication;
	objApplication.CreateObject(CLSID_Application);
	sys::InterfacePtr<IApplication> pIFApplication(objApplication);
	return pIFApplication;
}